﻿using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Extensions;
using Abp.MultiTenancy;
using AbpProjectTemplate.Components.Authorization;
using AbpProjectTemplate.Components.Identity;
using AbpProjectTemplate.Components.MultiTenancy;
using AbpProjectTemplate.Domain.Users;
using AbpProjectTemplate.Domain.Users.Members;
using AbpProjectTemplate.Web.Authentication.External;
using AbpProjectTemplate.Web.Authentication.JwtBearer;
using AbpProjectTemplate.Web.Models.TokenAuth;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using System.Transactions;
using AbpProjectTemplate.Extensions;
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Authentication.Cookies;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;

namespace AbpProjectTemplate.Web.Controllers
{
    /// <summary>
    /// 认证
    /// </summary>
    public class AuthenticationController : AppApiControllerBase
    {
        private readonly LogInManager _logInManager;
        private readonly ITenantCache _tenantCache;
        private readonly AppLoginResultTypeHelper _abpLoginResultTypeHelper;
        private readonly JwtHepler _jwtHepler;
        private readonly IExternalAuthManager _externalAuthManager;
        private readonly UserManager _userManager;

        public AuthenticationController(
            LogInManager logInManager,
            ITenantCache tenantCache,
            AppLoginResultTypeHelper abpLoginResultTypeHelper,
            JwtHepler jwtHepler, UserManager userManager,
            IExternalAuthManager externalAuthManager)
        {
            this._logInManager = logInManager;
            this._tenantCache = tenantCache;
            this._abpLoginResultTypeHelper = abpLoginResultTypeHelper;
            this._jwtHepler = jwtHepler;
            this._userManager = userManager;
            this._externalAuthManager = externalAuthManager;
        }

        #region 私有方法
        private string GetTenancyNameOrNull(string tenancyName)
        {
            if (!tenancyName.HasValue())
            {
                return null;
            }

            return this._tenantCache.GetOrNull(tenancyName)?.TenancyName;
        }

        private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName)
        {
            var loginResult = await this._logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);

            switch (loginResult.Result)
            {
                case AbpLoginResultType.Success:
                    return loginResult;
                default:
                    throw this._abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);
            }
        }
        #endregion

        /// <summary>
        /// 密码认证
        /// </summary>
        [HttpPost]
        public async Task<AuthenticateResultModel> Password([FromBody] AuthenticateModel input)
        {
            var loginResult = await this.GetLoginResultAsync(
                input.UserName,
                input.Password,
                this.GetTenancyNameOrNull(input.TenancyName)
            );

            var accessToken = this._jwtHepler.CreateAccessToken(loginResult.Identity);

            if (input.UseCookie)
            {
                if (!this._jwtHepler.Options.SupportCookieAuthentication)
                    throw new AppUserFriendlyException("系统不支持cookie认证！");
                this.HttpContext.Response.Cookies.Append(JwtAuthOptions.TokenCookieName, accessToken, new CookieOptions()
                {
                    Expires = DateTime.Now.Add(this._jwtHepler.Options.Expiration)
                });
            }
            return new AuthenticateResultModel
            {
                AccessToken = accessToken,
                //EncryptedAccessToken = this._jwtHepler.EncryptAccessToken(accessToken),
                ExpireInSeconds = (int)this._jwtHepler.Options.Expiration.TotalSeconds,
                UserId = loginResult.User.Id
            };
        }
        /// <summary>
        /// 第三方认证
        /// </summary>
        [HttpPost]
        public async Task<AuthenticateResultModel> External([FromBody] ExternalAuthenticateModel model)
        {

            var extInfo = await this._externalAuthManager.GetUserInfo(model.Provider, model.AccessCode);

            var userLoginInfo = new UserLoginInfo(extInfo.Provider, extInfo.ProviderKey, extInfo.Provider);
            //var userLoginInfo = new UserLoginInfo("WechatMiniProgram", "oW5UH0WKgYOrZOlaIDZ40F7Ng2z4", "WechatMiniProgram");
            var loginResult = await this._logInManager.LoginAsync(userLoginInfo);
            //注册
            if (loginResult.Result == AbpLoginResultType.UnknownExternalLogin)
            {
                using (var uow = this.UnitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
                {
                    var newUser = new Member()
                    {
                        //Head = externalUser.Head,
                        Name = extInfo.NickName,
                        UserName = extInfo.ProviderKey,
                    };
                    newUser.Logins.Add(new UserLogin() { LoginProvider = userLoginInfo.LoginProvider, ProviderKey = userLoginInfo.ProviderKey });
                    newUser.SetNormalizedNames();
                    var pwd = Domain.Users.User.CreateRandomPassword();
                    await this._userManager.CreateAsync(newUser, pwd);
                    await uow.CompleteAsync();
                    if (!newUser.IsActive)
                        throw new AppUserFriendlyException("请等待管理员审核。");

                }
                loginResult = await this._logInManager.LoginAsync(userLoginInfo);
            }
            //更新昵称和头像
            else if (loginResult.Result == AbpLoginResultType.Success)
            {
                var member = loginResult.User as Member;
                if (member != null)
                {
                    //if (!externalUser.Head.IsNullOrWhiteSpace())
                    //    member.Head = externalUser.Head;
                    if (!extInfo.NickName.IsNullOrWhiteSpace())
                        member.Name = extInfo.NickName;
                }
            }
            //登录失败
            if (loginResult.Result != AbpLoginResultType.Success)
                throw this._abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
                                loginResult.Result,
                                model.Provider.ToString(),
                                this.GetTenancyNameOrNull(null)
                            );

            var accessToken = this._jwtHepler.CreateAccessToken(loginResult.Identity);
            return new AuthenticateResultModel
            {
                AccessToken = accessToken,
                ExpireInSeconds = (int)this._jwtHepler.Options.Expiration.TotalSeconds,
                UserId = loginResult.User.Id
            };
        }
    }
}

